-module(tcp_acceptor).

-behaviour(gen_server).

-export([start_link/1]).

%% gen_server导出
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, 
		 terminate/2, code_change/3]).

-record(state, {sock, ref}).

%%--------------------------------------------------------------------

start_link(LSock) ->
    gen_server:start_link(?MODULE, LSock, []).

%%--------------------------------------------------------------------

init(LSock) ->
    gen_server:cast(self(), accept),
    {ok, #state{sock=LSock}}.

handle_call(_Request, _From, State) ->
    {reply, ok, State}.

%% accept
handle_cast(accept, State) ->
    accept(State);

handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info({inet_async, LSock, Ref, {ok, Sock}},
            State = #state{sock=LSock, ref=Ref}) ->

    %% patch up the socket so it looks like one we got from
    %% gen_tcp:accept/1
    %% {ok, Mod} = inet_db:lookup_socket(LSock),
	%% Mod =:= inet_tcp
	
	%% Returns the address and port for the other end of a connection
	{ok, Client} = inet:peername(Sock),
	
    inet_db:register_socket(Sock, inet_tcp),

    %% handle
	
	%% get options / set options ???
	case prim_inet:getopts(LSock, [active, nodelay, keepalive, 
								   delay_send, priority, tos]) of
        {ok, Opts} ->
			case prim_inet:setopts(Sock, Opts) of
				ok    -> ok;
				Error -> 
					gen_tcp:close(Sock),
					Error
			end;
        Error ->
            gen_tcp:close(Sock),
            Error
    end,
	
	%% 开启客户端reader进程,并保持监听进程不变
	{ok, Child} = supervisor:start_child(tcp_client_sup, []),
	ok = gen_tcp:controlling_process(Sock, Child),
	Child ! {go, Sock}, 
	
	io:format("client connect~p read pid ~p socket ~p~n", [Client, Child, Sock]),

    %% accept more
    accept(State);

handle_info({inet_async, LSock, Ref, {error, closed}},
            State=#state{sock=LSock, ref=Ref}) ->
    %% It would be wrong to attempt to restart the acceptor when we
    %% know this will fail.
    {stop, normal, State};

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, State) ->
	gen_tcp:close(State#state.sock),
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%--------------------------------------------------------------------

accept(State = #state{sock=LSock}) ->
    case prim_inet:async_accept(LSock, -1) of
        {ok, Ref} -> {noreply, State#state{ref=Ref}};
        Error     -> {stop, {cannot_accept, Error}, State}
    end.